﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using MathTools.Methods;

namespace AiKiDo2
{
    public partial class MainForm : Form
    {
        #region Constants

        private const double EPSILON = 1e-6;

        #endregion

        #region Fields

        private Timer refreshTimer;
        private bool shouldRefresh = false;

        private Eiler1 eiler1Method = new Eiler1();
        private Eiler2 eiler2Method = new Eiler2();

        private RungeCutta rungeCuttaMethod = new RungeCutta();
        private Adams adamsMethod = new Adams();

        private MathTools.AbstractCalculator currentCalc = null;

        private volatile double[ , ] lastAnswers;

        private double X0 = 1;
        private double Y0 = 1;
        private double Z0 = 1;

        private double R = 1;
        private double step = 1e-1;
        private int maxCount = int.MaxValue;

        #endregion

        public MainForm()
        {
            InitializeComponent();

            eiler1Method.FinishedEvent += new MathTools.AbstractCalculator.FinishedHandler( methodFinishedEvent );
            eiler2Method.FinishedEvent += new MathTools.AbstractCalculator.FinishedHandler( methodFinishedEvent );
            rungeCuttaMethod.FinishedEvent += new MathTools.AbstractCalculator.FinishedHandler( methodFinishedEvent );
            adamsMethod.FinishedEvent += new MathTools.AbstractCalculator.FinishedHandler( methodFinishedEvent );

            refreshTimer = new Timer();

            refreshTimer.Interval = 1000;
            refreshTimer.Tick += new EventHandler( refreshTimer_Tick );
            refreshTimer.Start();
        }

        void refreshTimer_Tick( object sender, EventArgs e )
        {
            if( currentCalc == null || !currentCalc.isStopped )
                return;

            if( shouldRefresh )
            {
                shouldRefresh = false;

                chartCanvas1.Refresh();

                toolStripProgressBar.Value = 0;

                statusLabel.Text = string.Empty;

            }
            else
            {
                toolStripProgressBar.Value = ( 100 * currentCalc.CurrentStep ) / currentCalc.MaxCount;
            }
        }

        private void methodFinishedEvent( double[,] answers )
        {
            MessageBox.Show( "Посчитано!" );

            chartCanvas1.SetPoints( answers, true );

            lastAnswers = answers;

            shouldRefresh = true;
        }

        private void commonCalculateBegin( MathTools.AbstractCalculator calc )
        {
            statusLabel.Text = "Высчиление.....";

            calc.R = R;
            calc.X0 = X0;
            calc.Y0 = Y0;
            calc.Z0 = Z0;

            calc.Step = step;
            calc.MaxCount = maxCount;

            currentCalc = calc;

            calc.beginSolveAsync( EPSILON );
        }

        #region Calculation events

        private void eilerMethod1_Click( object sender, EventArgs e )
        {
            commonCalculateBegin( eiler1Method );
        }

        private void eilerMethod2_Click( object sender, EventArgs e )
        {
            commonCalculateBegin( eiler2Method );
        }

        private void rungeCuttaMethod_Click( object sender, EventArgs e )
        {
            commonCalculateBegin( rungeCuttaMethod );
        }

        private void adamsMethod_Click( object sender, EventArgs e )
        {
            commonCalculateBegin( rungeCuttaMethod );
        }

        #endregion

        private void inputData_Click( object sender, EventArgs e )
        {
            using( InputDataForm form = new InputDataForm() )
            {
                form.X0 = X0;
                form.Y0 = Y0;
                form.Z0 = Z0;

                form.R = R;

                form.Step = step;
                form.MaxStepCount = maxCount;

                DialogResult res = form.ShowDialog();

                if( res != DialogResult.OK )
                    return;

                X0 = form.X0;
                Y0 = form.Y0;
                Z0 = form.Z0;

                R = form.R;

                step = form.Step;
                maxCount = form.MaxStepCount;
            }
        }

        private void toolStripMenuItem1_Click( object sender, EventArgs e )
        {
            chartCanvas1.Refresh();
        }

        private void stopMenuItem_Click( object sender, EventArgs e )
        {
            if( currentCalc != null )
                currentCalc.endSolveAsync( true );
        }
    }
}
